import { defineAsyncComponent, mergeProps, render as renderVNode, h as createVNode } from 'vue';

export default async function (App, options) {
  let component, instance, context, ctx, key, props, el, update, destroy;
  component = await defineAsyncComponent(App).__asyncLoader();
  options = Object.assign({}, options);
  context = options.context || this;
  ctx = context ? context._ || context : {};
  key = (Number(String(Math.random()).slice(2)) + Date.now()).toString(36);
  props = Object.assign({ key: key }, options.props);
  el = document.createDocumentFragment();

  destroy = () => {
    renderVNode(null, el);
    instance.component.update();
    instance.$ctx = null;
    instance.$el = null;
    instance.$update = null;
    instance.$destroy = null;
    instance = null;
    component = null;
    el = null;
    key = null;
    ctx = null;
    context = null;
    props = null;
    update = null;
    destroy = null;
  };
  update = (updateProps) => {
    if (typeof updateProps === 'function') {
      updateProps = updateProps(props);
    }
    if (instance && updateProps && typeof updateProps === 'object') {
      instance.component.props = mergeProps(instance.component.props, updateProps);
      instance.component.update();
    }
  };

  instance = createVNode(component, props, options.slots);
  instance.appContext = ctx._context || ctx.appContext || instance.appContext;
  instance.parent = ctx.root || ctx._instance;
  renderVNode(instance, el);
  instance.$ctx = instance.component.ctx;
  instance.$el = instance.el;
  instance.$update = update;
  instance.$destroy = destroy;
  return instance;
}
